home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / fasttext.c < prev    next >
C/C++ Source or Header  |  1994-02-09  |  27KB  |  1,402 lines

  1. /*
  2. Copyright 1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. #include "mint.h"
  8. #include "fasttext.h"
  9.  
  10. #ifdef FASTTEXT
  11.  
  12. #ifdef __GNUC__
  13. #define INLINE inline
  14. #define ITYPE long    /* gcc's optimizer likes 32 bit integers */
  15. #else
  16. #define INLINE
  17. #define ITYPE int
  18. #endif
  19.  
  20. #define CONDEV    (2)
  21.  
  22. static SCREEN *current;
  23. static short scr_usecnt;
  24.  
  25. static void paint P_((SCREEN *, int, char *)),
  26.      paint8c P_((SCREEN *, int, char *)),
  27.      paint816m P_((SCREEN *, int, char *));
  28.  
  29. INLINE static void curs_off P_((SCREEN *)), curs_on P_((SCREEN *));
  30. INLINE static void flash P_((SCREEN *));
  31. static void normal_putch P_((SCREEN *, int));
  32. static void escy_putch P_((SCREEN *, int));
  33. static void quote_putch P_((SCREEN *, int));
  34.  
  35. static    char *chartab[256];
  36.  
  37. #define MAX_PLANES 8
  38. static int fgmask[MAX_PLANES], bgmask[MAX_PLANES];
  39.  
  40. static long scrnsize;
  41.  
  42. short hardscroll;
  43. static char *hardbase, *oldbase;
  44.  
  45. typedef void (*Vfunc) P_((SCREEN *, int));
  46.  
  47. #define base *((char **)0x44eL)
  48. #define escy1 *((short *)0x4acL)
  49.  
  50. static Vfunc state;
  51.  
  52. static short hardline;
  53. static void (*vpaint) P_((SCREEN *, int, char *));
  54. static char *rowoff;
  55.  
  56. void init P_((void));
  57. void hardware_scroll P_((SCREEN *));
  58. INLINE static char *PLACE P_((SCREEN *, int, int));
  59. INLINE static void gotoxy P_((SCREEN *, int, int));
  60. INLINE static void clrline P_((SCREEN *, int));
  61. INLINE static void clear P_((SCREEN *));
  62. INLINE static void clrchar P_((SCREEN *, int, int));
  63. INLINE static void clrfrom P_((SCREEN *, int, int, int, int));
  64. INLINE static void delete_line P_((SCREEN *, int));
  65. INLINE static void insert_line P_((SCREEN *, int));
  66. static void setbgcol P_((SCREEN *, int));
  67. static void setfgcol P_((SCREEN *, int));
  68. static void setcurs P_((SCREEN *, int));
  69. static void putesc P_((SCREEN *, int));
  70. static void escy1_putch P_((SCREEN *, int));
  71. INLINE static void put_ch P_((SCREEN *, int));
  72.  
  73. /* routines for flashing the cursor for screen v */
  74. /* flash(v): invert the character currently under the cursor */
  75.  
  76. INLINE static void
  77. flash(v)
  78.     SCREEN *v;
  79. {
  80.     char *place;
  81.     ITYPE i, j, vplanes;
  82.  
  83.     vplanes = v->planes + v->planes;
  84.     place = v->cursaddr;
  85.  
  86.     for (j = v->cheight; j > 0; --j) {
  87.         for (i = 0; i < vplanes; i+=2)
  88.             place[i] = ~place[i];
  89.  
  90.         place += v->planesiz;
  91.     }
  92.     v->curstimer = v->period;
  93. }
  94.  
  95. /* make sure the cursor is off */
  96.  
  97. INLINE
  98. static void
  99. curs_off(v)
  100.     SCREEN *v;
  101. {
  102.     if (v->flags & CURS_ON) {
  103.         if (v->flags & CURS_FSTATE) {
  104.             flash(v);
  105.             v->flags &= ~CURS_FSTATE;
  106.         }
  107.     }
  108. }
  109.  
  110. /* OK, show the cursor again (if appropriate) */
  111.  
  112. INLINE static void
  113. curs_on(v)
  114.     SCREEN *v;
  115. {
  116.     if (v->hidecnt) return;
  117.  
  118.     if (v->flags & CURS_ON) {
  119. #if 0
  120.     /* if the cursor is flashing, we cheat a little and leave it off
  121.      * to be turned on again (if necessary) by the VBL routine
  122.      */
  123.         if (v->flags & CURS_FLASH) {
  124.             v->curstimer = 2;
  125.             return;
  126.         }
  127. #endif
  128.         if (!(v->flags & CURS_FSTATE)) {
  129.             v->flags |= CURS_FSTATE;
  130.             flash(v);
  131.         }
  132.     }
  133. }
  134.  
  135. void
  136. init()
  137. {
  138.     SCREEN *v;
  139.     int i, j;
  140.     char *data, *foo;
  141.     static char chardata[256*16];
  142.     register int linelen;
  143.  
  144.     foo = lineA0();
  145.     v = (SCREEN *)(foo - 346);
  146.     
  147.     /* Ehem... The screen might be bigger than 32767 bytes.
  148.        Let's do some casting... 
  149.        Erling
  150.     */
  151.     linelen = v->linelen;
  152.     scrnsize = (v->maxy+1)*(long)linelen;
  153.     rowoff = (char *)kmalloc((long)((v->maxy+1) * sizeof(long)));
  154.     if (rowoff == 0) {
  155.         FATAL("Insufficient memory for screen offset table!");
  156.     } else {
  157.         long off, *lptr = (long *)rowoff;
  158.         for (i=0, off=0; i<=v->maxy; i++) {
  159.             *lptr++ = off;
  160.             off += linelen;
  161.         }
  162.     }
  163.     if (hardscroll == -1) {
  164.     /* request for auto-setting */
  165.         hardscroll = v->maxy+1;
  166.     }
  167.     if (hardscroll > 0) {
  168.         if (!hardbase)
  169.             hardbase = (char *)(((long)kcore(SCNSIZE(v)+256L)+255L)
  170.                        & 0xffffff00L);
  171.  
  172.         if (hardbase == 0) {
  173.             ALERT("Insufficient memory for hardware scrolling!");
  174.         } else {
  175.             v->curstimer = 0x7f;
  176.             quickmove(hardbase, base, scrnsize);
  177.             v->cursaddr = v->cursaddr + (hardbase - base);
  178.             oldbase = base;
  179.             base = hardbase;
  180.             Setscreen(hardbase, hardbase, -1);
  181.             v->curstimer = v->period;
  182.         }
  183.     }
  184.     hardline = 0;
  185.     if (v->cheight == 8 && v->planes == 2) {
  186.         foo = &chardata[0];
  187.         vpaint = paint8c;
  188.         for (i = 0; i < 256; i++) {
  189.             chartab[i] = foo;
  190.             data = v->fontdata + i;
  191.             for (j = 0; j < 8; j++) {
  192.                 *foo++ = *data;
  193.                 data += v->form_width;
  194.             }
  195.         }
  196.     } else if ((v->cheight == 16 || v->cheight == 8) && v->planes == 1) {
  197.         foo = &chardata[0];
  198.         vpaint = paint816m;
  199.         for (i = 0; i < 256; i++) {
  200.             chartab[i] = foo;
  201.             data = v->fontdata + i;
  202.             for (j = 0; j < v->cheight; j++) {
  203.                 *foo++ = *data;
  204.                 data += v->form_width;
  205.             }
  206.         }
  207.     }
  208.     else
  209.         vpaint = paint;
  210.  
  211.     if (v->hidecnt == 0) {
  212.     /*
  213.      * make sure the cursor is set up correctly and turned on
  214.      */
  215.         (void)Cursconf(0,0);    /* turn cursor off */
  216.  
  217.         v->flags &= ~CURS_FSTATE;
  218.  
  219.     /* now turn the cursor on the way we like it */
  220.         v->curstimer = v->period;
  221.         v->hidecnt = 0;
  222.         v->flags |= CURS_ON;
  223.         curs_on(v);
  224.     } else {
  225.         (void)Cursconf(0,0);
  226.         v->flags &= ~CURS_ON;
  227.         v->hidecnt = 1;
  228.     }
  229.  
  230.     current = v;
  231.     /* setup bgmask and fgmask */
  232.     setbgcol(v, v->bgcol);
  233.     setfgcol(v, v->fgcol);
  234.     state = normal_putch;
  235. }
  236.  
  237. /*
  238.  * PLACE(v, x, y): the address corresponding to the upper left hand corner of
  239.  * the character at position (x,y) on screen v
  240.  */
  241. INLINE static
  242. char *PLACE(v, x, y)
  243.     SCREEN *v;
  244.     int x, y;
  245. {
  246.     char *place;
  247.     int i, j;
  248.  
  249.     place = base + x;
  250.     if (y == v->maxy)
  251.         place += scrnsize - v->linelen;
  252.     else if (y) {
  253.         y+=y;    /* Make Y into index for longword array. */
  254.         y+=y;    /* Two word-size adds are faster than a 2-bit shift. */
  255.         place += *(long *)(rowoff + y);
  256.     }
  257.     if ((j = v->planes-1)) {
  258.         i = (x & 0xfffe);
  259.         do place += i;
  260.         while (--j);
  261.     }
  262.     return place;
  263. }
  264.  
  265. /*
  266.  * paint(v, c, place): put character 'c' at position 'place' on screen
  267.  * v. It is assumed that x, y are proper coordinates!
  268.  * Specialized versions (paint8c and paint816m) of this routine follow;
  269.  * they assume 8 line high characters, medium res. and 8 or 16 line/mono,
  270.  * respectively.
  271.  */
  272.  
  273. static void
  274. paint(v, c, place)
  275.     SCREEN *v;
  276.     int c;
  277.     char *place;
  278. {
  279.     char *data, d, doinverse;
  280.     ITYPE j, planecount;
  281.     int vplanes;
  282.     long vform_width, vplanesiz;
  283.  
  284.     vplanes = v->planes;
  285.  
  286.     data = v->fontdata + c;
  287.     doinverse = (v->flags & FINVERSE) ? 0xff : 0;
  288.     vform_width = v->form_width;
  289.     vplanesiz = v->planesiz;
  290.  
  291.     for (j = v->cheight; j > 0; --j) {
  292.         d = *data ^ doinverse;
  293.         for (planecount = 0; planecount < vplanes; planecount++)
  294.           place[planecount << 1]
  295.             = ((d & (char) fgmask[planecount])
  296.                | (~d & (char) bgmask[planecount]));
  297.         place += vplanesiz;
  298.         data += vform_width;
  299.     }
  300. }
  301.  
  302. static void
  303. paint8c(v, c, place)
  304.     SCREEN *v;
  305.     int c;
  306.     char *place;
  307. {
  308.     char *data;
  309.     char d, doinverse;
  310.     char bg0, bg1, fg0, fg1;
  311.     long vplanesiz;
  312.  
  313.     data = chartab[c];
  314.  
  315.     doinverse = (v->flags & FINVERSE) ? 0xff : 0;
  316.     vplanesiz = v->planesiz;
  317.     bg0 = bgmask[0];
  318.     bg1 = bgmask[1];
  319.     fg0 = fgmask[0];
  320.     fg1 = fgmask[1];
  321.  
  322.     if (!doinverse && !bg0 && !bg1 && fg0 && fg1) {
  323.         /* line 1 */
  324.         d = *data++;
  325.         *place = d;
  326.         place[2] = d;
  327.         place += vplanesiz;
  328.  
  329.         /* line 2 */
  330.         d = *data++;
  331.         *place = d;
  332.         place[2] = d;
  333.         place += vplanesiz;
  334.  
  335.         /* line 3 */
  336.         d = *data++;
  337.         *place = d;
  338.         place[2] = d;
  339.         place += vplanesiz;
  340.  
  341.         /* line 4 */
  342.         d = *data++;
  343.         *place = d;
  344.         place[2] = d;
  345.         place += vplanesiz;
  346.  
  347.         /* line 5 */
  348.         d = *data++;
  349.         *place = d;
  350.         place[2] = d;
  351.         place += vplanesiz;
  352.  
  353.         /* line 6 */
  354.         d = *data++;
  355.         *place = d;
  356.         place[2] = d;
  357.         place += vplanesiz;
  358.  
  359.         /* line 7 */
  360.         d = *data++;
  361.         *place = d;
  362.         place[2] = d;
  363.         place += vplanesiz;
  364.  
  365.         /* line 8 */
  366.         d = *data;
  367.         *place = d;
  368.         place[2] = d;
  369.     } else {
  370.         /* line 1 */
  371.         d = *data++ ^ doinverse;
  372.         *place = ((d & fg0) | (~d & bg0));
  373.         place[2] = ((d & fg1) | (~d & bg1));
  374.         place += vplanesiz;
  375.  
  376.         /* line 2 */
  377.         d = *data++ ^ doinverse;
  378.         *place = ((d & fg0) | (~d & bg0));
  379.         place[2] = ((d & fg1) | (~d & bg1));
  380.         place += vplanesiz;
  381.  
  382.         /* line 3 */
  383.         d = *data++ ^ doinverse;
  384.         *place = ((d & fg0) | (~d & bg0));
  385.         place[2] = ((d & fg1) | (~d & bg1));
  386.         place += vplanesiz;
  387.  
  388.         /* line 4 */
  389.         d = *data++ ^ doinverse;
  390.         *place = ((d & fg0) | (~d & bg0));
  391.         place[2] = ((d & fg1) | (~d & bg1));
  392.         place += vplanesiz;
  393.  
  394.         /* line 5 */
  395.         d = *data++ ^ doinverse;
  396.         *place = ((d & fg0) | (~d & bg0));
  397.         place[2] = ((d & fg1) | (~d & bg1));
  398.         place += vplanesiz;
  399.  
  400.         /* line 6 */
  401.         d = *data++ ^ doinverse;
  402.         *place = ((d & fg0) | (~d & bg0));
  403.         place[2] = ((d & fg1) | (~d & bg1));
  404.         place += vplanesiz;
  405.  
  406.         /* line 7 */
  407.         d = *data++ ^ doinverse;
  408.         *place = ((d & fg0) | (~d & bg0));
  409.         place[2] = ((d & fg1) | (~d & bg1));
  410.         place += vplanesiz;
  411.  
  412.         /* line 8 */
  413.         d = *data ^ doinverse;
  414.         *place = ((d & fg0) | (~d & bg0));
  415.         place[2] = ((d & fg1) | (~d & bg1));
  416.     }
  417. }
  418.  
  419. static void
  420. paint816m(v, c, place)
  421.     SCREEN *v;
  422.     int c;
  423.     char *place;
  424. {
  425.     char *data;
  426.     char d, doinverse;
  427.     long vplanesiz;
  428.  
  429.     data = chartab[c];
  430.     doinverse = (v->flags & FINVERSE) ? 0xff : 0;
  431.     doinverse ^= bgmask[0];
  432.     vplanesiz = v->planesiz;
  433.  
  434.     if (bgmask[0] == fgmask[0])
  435.       {
  436.         /* fgcol and bgcol are the same -- easy */
  437.         d = (char) bgmask[0];
  438.         *place = d;
  439.         place += vplanesiz;
  440.         *place = d;
  441.         place += vplanesiz;
  442.         *place = d;
  443.         place += vplanesiz;
  444.         *place = d;
  445.         place += vplanesiz;
  446.         *place = d;
  447.         place += vplanesiz;
  448.         *place = d;
  449.         place += vplanesiz;
  450.         *place = d;
  451.         place += vplanesiz;
  452.         *place = d;
  453.         if (v->cheight == 8)
  454.         return;
  455.         place += vplanesiz;
  456.         *place = d;
  457.         place += vplanesiz;
  458.         *place = d;
  459.         place += vplanesiz;
  460.         *place = d;
  461.         place += vplanesiz;
  462.         *place = d;
  463.         place += vplanesiz;
  464.         *place = d;
  465.         place += vplanesiz;
  466.         *place = d;
  467.         place += vplanesiz;
  468.         *place = d;
  469.         place += vplanesiz;
  470.         *place = d;
  471.       }
  472.     else if (!doinverse) {
  473.         /* line 1 */
  474.         d = *data++;
  475.         *place = d;
  476.         place += vplanesiz;
  477.  
  478.         /* line 2 */
  479.         d = *data++;
  480.         *place = d;
  481.         place += vplanesiz;
  482.  
  483.         /* line 3 */
  484.         d = *data++;
  485.         *place = d;
  486.         place += vplanesiz;
  487.  
  488.         /* line 4 */
  489.         d = *data++;
  490.         *place = d;
  491.         place += vplanesiz;
  492.  
  493.         /* line 5 */
  494.         d = *data++;
  495.         *place = d;
  496.         place += vplanesiz;
  497.  
  498.         /* line 6 */
  499.         d = *data++;
  500.         *place = d;
  501.         place += vplanesiz;
  502.  
  503.         /* line 7 */
  504.         d = *data++;
  505.         *place = d;
  506.         place += vplanesiz;
  507.  
  508.         /* line 8 */
  509.         d = *data++;
  510.         *place = d;
  511.  
  512.         if (v->cheight == 8)
  513.             return;
  514.  
  515.         place += vplanesiz;
  516.  
  517.         /* line 9 */
  518.         d = *data++;
  519.         *place = d;
  520.         place += vplanesiz;
  521.  
  522.         /* line 10 */
  523.         d = *data++;
  524.         *place = d;
  525.         place += vplanesiz;
  526.  
  527.         /* line 11 */
  528.         d = *data++;
  529.         *place = d;
  530.         place += vplanesiz;
  531.  
  532.         /* line 12 */
  533.         d = *data++;
  534.         *place = d;
  535.         place += vplanesiz;
  536.  
  537.         /* line 13 */
  538.         d = *data++;
  539.         *place = d;
  540.         place += vplanesiz;
  541.  
  542.         /* line 14 */
  543.         d = *data++;
  544.         *place = d;
  545.         place += vplanesiz;
  546.  
  547.         /* line 15 */
  548.         d = *data++;
  549.         *place = d;
  550.         place += vplanesiz;
  551.  
  552.         /* line 16 */
  553.         d = *data;
  554.         *place = d;
  555.     } else {
  556.         /* line 1 */
  557.         d = ~*data++;
  558.         *place = d;
  559.         place += vplanesiz;
  560.  
  561.         /* line 2 */
  562.         d = ~*data++;
  563.         *place = d;
  564.         place += vplanesiz;
  565.  
  566.         /* line 3 */
  567.         d = ~*data++;
  568.         *place = d;
  569.         place += vplanesiz;
  570.  
  571.         /* line 4 */
  572.         d = ~*data++;
  573.         *place = d;
  574.         place += vplanesiz;
  575.  
  576.         /* line 5 */
  577.         d = ~*data++;
  578.         *place = d;
  579.         place += vplanesiz;
  580.  
  581.         /* line 6 */
  582.         d = ~*data++;
  583.         *place = d;
  584.         place += vplanesiz;
  585.  
  586.         /* line 7 */
  587.         d = ~*data++;
  588.         *place = d;
  589.         place += vplanesiz;
  590.  
  591.         /* line 8 */
  592.         d = ~*data++;
  593.         *place = d;
  594.  
  595.         if (v->cheight == 8)
  596.             return;
  597.  
  598.         place += vplanesiz;
  599.  
  600.         /* line 9 */
  601.         d = ~*data++;
  602.         *place = d;
  603.         place += vplanesiz;
  604.  
  605.         /* line 10 */
  606.         d = ~*data++;
  607.         *place = d;
  608.         place += vplanesiz;
  609.  
  610.         /* line 11 */
  611.         d = ~*data++;
  612.         *place = d;
  613.         place += vplanesiz;
  614.  
  615.         /* line 12 */
  616.         d = ~*data++;
  617.         *place = d;
  618.         place += vplanesiz;
  619.  
  620.         /* line 13 */
  621.         d = ~*data++;
  622.         *place = d;
  623.         place += vplanesiz;
  624.  
  625.         /* line 14 */
  626.         d = ~*data++;
  627.         *place = d;
  628.         place += vplanesiz;
  629.  
  630.         /* line 15 */
  631.         d = ~*data++;
  632.         *place = d;
  633.         place += vplanesiz;
  634.  
  635.         /* line 16 */
  636.         d = ~*data;
  637.         *place = d;
  638.     }
  639. }
  640.  
  641. /*
  642.  * gotoxy (v, x, y): move current cursor address of screen v to (x, y)
  643.  * makes sure that (x, y) will be legal
  644.  */
  645.  
  646. INLINE static void
  647. gotoxy(v, x, y)
  648.     SCREEN *v;
  649.     int x, y;
  650. {
  651.     if (x > v->maxx) x = v->maxx;
  652.     else if (x < 0) x = 0;
  653.     if (y > v->maxy) y = v->maxy;
  654.     else if (y < 0) y = 0;
  655.  
  656.     v->cx = x;
  657.     v->cy = y;
  658.     v->cursaddr = PLACE(v, x, y);
  659. }
  660.  
  661. /*
  662.  * clrline(v, r): clear line r of screen v
  663.  */
  664.  
  665. INLINE static void
  666. clrline(v, r)
  667.     SCREEN *v;
  668.     int r;
  669. {
  670.     int *dst, *m;
  671.     long nwords;
  672.     int i, vplanes;
  673.  
  674.     /* Hey, again the screen might be bigger than 32767 bytes.
  675.        Do another cast... */
  676.     r += r;
  677.     r += r;
  678.     dst = (int *)(base + *(long *)(rowoff+r));
  679.     if (v->bgcol == 0)
  680.       zero((char *)dst, v->linelen);
  681.     else
  682.       {
  683.         /* do it the hard way */
  684.         vplanes = v->planes;
  685.         for (nwords = v->linelen >> 1; nwords > 0; nwords -= vplanes)
  686.           {
  687.         m = bgmask;
  688.         for (i = 0; i < vplanes; i++)
  689.           *dst++ = *m++;
  690.           }
  691.       }
  692. }
  693.     
  694. /*
  695.  * clear(v): clear the whole screen v
  696.  */
  697.  
  698. INLINE static void
  699. clear(v)
  700.     SCREEN *v;
  701. {
  702.     int i, vplanes;
  703.     int *dst, *m;
  704.     long nwords;
  705.  
  706.     if (v->bgcol == 0)
  707.       zero(base, scrnsize);
  708.     else
  709.       {
  710.         /* do it the hard way */
  711.         dst = (int *) base;
  712.         vplanes = v->planes;
  713.         for (nwords = scrnsize >> 1; nwords > 0; nwords -= vplanes)
  714.           {
  715.         m = bgmask;
  716.         for (i = 0; i < vplanes; i++)
  717.           *dst++ = *m++;
  718.           }
  719.       }
  720. }
  721.  
  722. /*
  723.  * clrchar(v, x, y): clear the (x,y) position on screen v
  724.  */
  725.  
  726. INLINE static void
  727. clrchar(v, x, y)
  728.     SCREEN *v;
  729.     int x, y;
  730. {
  731.     int i, j, vplanes;
  732.     char *place;
  733.     int *m;
  734.  
  735.     vplanes = v->planes + v->planes;
  736.  
  737.     place = PLACE(v, x, y);
  738.  
  739.     for (j = v->cheight; j > 0; --j) {
  740.         m = bgmask;
  741.         for (i = 0; i < vplanes; i += 2)
  742.             place[i] = (char) *m++;
  743.         place += v->planesiz;
  744.     }
  745. }
  746.  
  747. /*
  748.  * clrfrom(v, x1, y1, x2, y2): clear screen v from position (x1,y1) to
  749.  * position (x2, y2) inclusive. It is assumed that y2 >= y1.
  750.  */
  751.  
  752. INLINE static void
  753. clrfrom(v, x1, y1, x2, y2)
  754.     SCREEN *v;
  755.     int x1,y1,x2,y2;
  756. {
  757.     int i;
  758.  
  759.     for (i = x1; i <= v->maxx; i++)
  760.         clrchar(v, i, y1);
  761.     if (y2 > y1) {
  762.         for (i = 0; i <= x2; i++)
  763.             clrchar(v, i, y2);
  764.         for (i = y1+1; i < y2; i++)
  765.             clrline(v, i);
  766.     }
  767. }
  768.  
  769. /*
  770.  * scroll a screen in hardware; if we still have hardware scrolling lines left,
  771.  * just move the physical screen base, otherwise copy the screen back to the
  772.  * hardware base and start over
  773.  */
  774. void
  775. hardware_scroll(v)
  776.     SCREEN *v;
  777. {
  778.  
  779.     ++hardline;
  780.     if (hardline < hardscroll) { /* just move the screen */
  781.         base += v->linelen;
  782.     } else {
  783.         hardline = 0;
  784.         quickmove(hardbase, base + v->linelen, scrnsize - v->linelen);
  785.         base = hardbase;
  786.     }
  787.     v->cursaddr = PLACE(v, v->cx, v->cy);
  788.     Setscreen(base, base, -1);
  789. }
  790.  
  791. /*
  792.  * delete_line(v, r): delete line r of screen v. The screen below this
  793.  * line is scrolled up, and the bottom line is cleared.
  794.  */
  795.  
  796. #define scroll(v) delete_line(v, 0)
  797.  
  798. INLINE static void
  799. delete_line(v, r)
  800.     SCREEN *v;
  801.     int r;
  802. {
  803.     long *src, *dst, nbytes;
  804.  
  805.     if (r == 0) {
  806.         if (hardbase) {
  807.             hardware_scroll(v);
  808.             clrline(v, v->maxy);
  809.             return;
  810.         }
  811.         nbytes = scrnsize - v->linelen;
  812.     } else {
  813.         register int i = v->maxy - r;
  814.         i += i;
  815.         i += i;
  816.         nbytes = *(long *)(rowoff+i);
  817.     }
  818.  
  819.     /* Sheeze, how many times do we really have to cast... 
  820.        Erling.    
  821.     */
  822.  
  823.     r += r;
  824.     r += r;
  825.     dst = (long *)(base + *(long *)(rowoff + r));
  826.     src = (long *)( ((long)dst) + v->linelen);
  827.  
  828.     quickmove(dst, src, nbytes);
  829.  
  830. /* clear the last line */
  831.     clrline(v, v->maxy);
  832. }
  833.  
  834. /*
  835.  * insert_line(v, r): scroll all of the screen starting at line r down,
  836.  * and then clear line r.
  837.  */
  838.  
  839. INLINE static void
  840. insert_line(v, r)
  841.     SCREEN *v;
  842.     int r;
  843. {
  844.     long *src, *dst;
  845.     int i, j, linelen;
  846.  
  847.     i = v->maxy - 1;
  848.     i += i;
  849.     i += i;
  850.     j = r+r;
  851.     j += j;
  852.     linelen = v->linelen;
  853.     src = (long *)(base + *(long *)(rowoff + i));
  854.     dst = (long *)((long)src + linelen);
  855.     for (; i >= j ; i -= 4) {
  856.     /* move line i to line i+1 */
  857.         quickmove(dst, src, linelen);
  858.         dst = src;
  859.         src = (long *)((long) src - linelen);
  860.     }
  861.  
  862. /* clear line r */
  863.     clrline(v, r);
  864. }
  865.  
  866. /*
  867.  * special states for handling ESC b x and ESC c x. Note that for now,
  868.  * color is ignored.
  869.  */
  870.  
  871. static void
  872. setbgcol(v, c)
  873.     SCREEN *v;
  874.     int c;
  875. {
  876.     int i;
  877.  
  878.     v->bgcol = c & ((1 << v->planes)-1);
  879.     for (i = 0; i < v->planes; i++)
  880.         bgmask[i] = (v->bgcol & (1 << i)) ? -1 : 0;
  881.     state = normal_putch;
  882. }
  883.  
  884. static void
  885. setfgcol(v, c)
  886.     SCREEN *v;
  887.     int c;
  888. {
  889.     int i;
  890.  
  891.     v->fgcol = c & ((1 << v->planes)-1);
  892.     for (i = 0; i < v->planes; i++)
  893.         fgmask[i] = (v->fgcol & (1 << i)) ? -1 : 0;
  894.     state = normal_putch;
  895. }
  896.  
  897. static void
  898. setcurs(v, c)
  899.     SCREEN *v;
  900.     int c;
  901. {
  902.     c -= ' ';
  903.     if (!c) {
  904.         v->flags &= ~CURS_FLASH;
  905.     } else {
  906.         v->flags |= CURS_FLASH;
  907.         v->period = (unsigned char) c;
  908.     }
  909.     state = normal_putch;
  910. }
  911.  
  912. static void
  913. quote_putch(v, c)
  914.     SCREEN *v;
  915.     int c;
  916. {
  917.     (*vpaint)(v, c, v->cursaddr);
  918.     state = normal_putch;
  919. }
  920.  
  921. /*
  922.  * putesc(v, c): handle the control sequence ESC c
  923.  */
  924.  
  925. static void
  926. putesc(v, c)
  927.     SCREEN *v;
  928.     int c;
  929. {
  930.     int i;
  931.     int cx, cy;
  932.  
  933.     cx = v->cx; cy = v->cy;
  934.  
  935.     switch (c) {
  936.     case 'A':        /* cursor up */
  937.         if (cy) {
  938. moveup:            v->cy = --cy;
  939.             v->cursaddr -= v->linelen;
  940.         }
  941.         break;
  942.     case 'B':        /* cursor down */
  943.         if (cy < v->maxy) {
  944.             v->cy = ++cy;
  945.             v->cursaddr += v->linelen;
  946.         }
  947.         break;
  948.     case 'C':        /* cursor right */
  949.         if (cx < v->maxx) {
  950.             if ((i = v->planes-1) && (cx & 1))
  951.                 v->cursaddr += i + i;
  952.             v->cx = ++cx;
  953.             v->cursaddr++;
  954.         }
  955.         break;
  956.     case 'D':        /* cursor left */
  957.         if (cx) {
  958.             v->cx = --cx;
  959.             v->cursaddr--;
  960.             if ((i = v->planes-1) && (cx & 1))
  961.                 v->cursaddr -= i + i;
  962.         }
  963.         break;
  964.     case 'E':        /* clear home */
  965.         clear(v);
  966.         /* fall through... */
  967.     case 'H':        /* cursor home */
  968.         v->cx = 0; v->cy = 0;
  969.         v->cursaddr = base;
  970.         break;
  971.     case 'I':        /* cursor up, insert line */
  972.         if (cy == 0) {
  973.             insert_line(v, 0);
  974.         }
  975.         else
  976.             goto moveup;
  977.         break;
  978.     case 'J':        /* clear below cursor */
  979.         clrfrom(v, cx, cy, v->maxx, v->maxy);
  980.         break;
  981.     case 'K':        /* clear remainder of line */
  982.         clrfrom(v, cx, cy, v->maxx, cy);
  983.         break;
  984.     case 'L':        /* insert a line */
  985.         v->cx = 0;
  986.         i = cy + cy;
  987.         i += i;
  988.         v->cursaddr = base + *(long *)(rowoff + i);
  989.         insert_line(v, cy);
  990.         break;
  991.     case 'M':        /* delete line */
  992.         v->cx = 0;
  993.         i = cy + cy;
  994.         i += i;
  995.         v->cursaddr = base + *(long *)(rowoff + i);
  996.         delete_line(v, cy);
  997.         break;
  998.     case 'Q':        /* EXTENSION: quote-next-char */
  999.         state = quote_putch;
  1000.         return;
  1001.     case 'Y':
  1002.         state = escy_putch;
  1003.         return;        /* YES, this should be 'return' */
  1004.  
  1005.     case 'b':
  1006.         state = setfgcol;
  1007.         return;
  1008.     case 'c':
  1009.         state = setbgcol;
  1010.         return;
  1011.     case 'd':        /* clear to cursor position */
  1012.         clrfrom(v, 0, 0, cx, cy);
  1013.         break;
  1014.     case 'e':        /* enable cursor */
  1015.         v->flags |= CURS_ON;
  1016.         v->hidecnt = 1;    /* so --v->hidecnt shows the cursor */
  1017.         break;
  1018.     case 'f':        /* cursor off */
  1019.         v->hidecnt++;
  1020.         v->flags &= ~CURS_ON;
  1021.         break;
  1022.     case 'j':        /* save cursor position */
  1023.         v->savex = v->cx;
  1024.         v->savey = v->cy;
  1025.         break;
  1026.     case 'k':        /* restore saved position */
  1027.         gotoxy(v, v->savex, v->savey);
  1028.         break;
  1029.     case 'l':        /* clear line */
  1030.         v->cx = 0;
  1031.         i = cy + cy;
  1032.         i += i;
  1033.         v->cursaddr = base + *(long *)(rowoff + i);
  1034.         clrline(v, cy);
  1035.         break;
  1036.     case 'o':        /* clear from start of line to cursor */
  1037.         clrfrom(v, 0, cy, cx, cy);
  1038.         break;
  1039.     case 'p':        /* reverse video on */
  1040.         v->flags |= FINVERSE;
  1041.         break;
  1042.     case 'q':        /* reverse video off */
  1043.         v->flags &= ~FINVERSE;
  1044.         break;
  1045.     case 't':        /* EXTENSION: set cursor flash rate */
  1046.         state = setcurs;
  1047.         return;
  1048.     case 'v':        /* wrap on */
  1049.         v->flags |= FWRAP;
  1050.         break;
  1051.     case 'w':
  1052.         v->flags &= ~FWRAP;
  1053.         break;
  1054.     }
  1055.     state = normal_putch;
  1056. }
  1057.  
  1058. /*
  1059.  * escy1_putch(v, c): for when an ESC Y + char has been seen
  1060.  */
  1061. static void
  1062. escy1_putch(v, c)
  1063.     SCREEN *v;
  1064.     int c;
  1065. {
  1066.     gotoxy(v, c - ' ', escy1 - ' ');
  1067.     state = normal_putch;
  1068. }
  1069.  
  1070. /*
  1071.  * escy_putch(v, c): for when an ESC Y has been seen
  1072.  */
  1073. static void
  1074. escy_putch(v, c)
  1075.     SCREEN *v;
  1076.     int c;
  1077. {
  1078.     UNUSED(v);
  1079.     escy1 = c;
  1080.     state = escy1_putch;
  1081. }
  1082.  
  1083. /*
  1084.  * normal_putch(v, c): put character 'c' on screen 'v'. This is the default
  1085.  * for when no escape, etc. is active
  1086.  */
  1087.  
  1088. static void
  1089. normal_putch(v, c)
  1090.     SCREEN *v;
  1091.     int c;
  1092. {
  1093.     register int i;
  1094.  
  1095. /* control characters */
  1096.     if (c < ' ') {
  1097.         switch (c) {
  1098.         case '\r':
  1099. col0:            v->cx = 0;
  1100.             i = v->cy + v->cy;
  1101.             i += i;
  1102.             v->cursaddr = base + *(long *)(rowoff + i);
  1103.             return;
  1104.         case '\n':
  1105.             if (v->cy == v->maxy) {
  1106.                 scroll(v);
  1107.             } else {
  1108.                 v->cy++;
  1109.                 v->cursaddr += v->linelen;
  1110.             }
  1111.             return;
  1112.         case '\b':
  1113.             if (v->cx) {
  1114.                 v->cx--;
  1115.                 v->cursaddr--;
  1116.                 if ((i = v->planes-1) && (v->cx & 1))
  1117.                     v->cursaddr -= i+i;
  1118.             }
  1119.             return;
  1120.         case '\007':        /* BELL */
  1121.             (void)bconout(CONDEV, 7);
  1122.             return;
  1123.         case '\033':        /* ESC */
  1124.             state = putesc;
  1125.             return;
  1126.         case '\t':
  1127.             if (v->cx < v->maxx) {
  1128.             /* this can't be register for an ANSI compiler */
  1129.                 union {
  1130.                     long l;
  1131.                     short i[2];
  1132.                 } j;
  1133.                 j.l = 0;
  1134.                 j.i[1] = 8 - (v->cx & 7);
  1135.                 v->cx += j.i[1];
  1136.                 if (v->cx - v->maxx > 0) {
  1137.                     j.i[1] = v->cx - v->maxx;
  1138.                     v->cx = v->maxx;
  1139.                 }
  1140.                 v->cursaddr += j.l;
  1141.                 if ((i = v->planes-1)) {
  1142.                     if (j.l & 1)
  1143.                         j.i[1]++;
  1144.                     do v->cursaddr += j.l;
  1145.                     while (--i);
  1146.                 }
  1147.             }
  1148.             return;
  1149.         default:
  1150.             return;
  1151.         }
  1152.     }
  1153.  
  1154.     (*vpaint)(v, c, v->cursaddr);
  1155.     v->cx++;
  1156.     if (v->cx > v->maxx) {
  1157.         if (v->flags & FWRAP) {
  1158.             normal_putch(v, '\n');
  1159.             goto col0;
  1160.         } else {
  1161.             v->cx = v->maxx;
  1162.         }
  1163.     } else {
  1164.         v->cursaddr++;
  1165.         if ((i = v->planes-1) && !(v->cx & 1))    /* new word */
  1166.             v->cursaddr += i + i;
  1167.     }
  1168. }
  1169.  
  1170. INLINE static void
  1171. put_ch(v, c)
  1172.     SCREEN *v;
  1173.     int c;
  1174. {
  1175.     (*state)(v, c & 0x00ff);
  1176. }
  1177.  
  1178. static long ARGS_ON_STACK screen_open    P_((FILEPTR *f));
  1179. static long ARGS_ON_STACK screen_read    P_((FILEPTR *f, char *buf, long nbytes));
  1180. static long ARGS_ON_STACK screen_write P_((FILEPTR *f, const char *buf, long nbytes));
  1181. static long ARGS_ON_STACK screen_lseek P_((FILEPTR *f, long where, int whence));
  1182. static long ARGS_ON_STACK screen_ioctl P_((FILEPTR *f, int mode, void *buf));
  1183. static long ARGS_ON_STACK screen_close P_((FILEPTR *f, int pid));
  1184. static long ARGS_ON_STACK screen_select P_((FILEPTR *f, long p, int mode));
  1185. static void ARGS_ON_STACK screen_unselect P_((FILEPTR *f, long p, int mode));
  1186.  
  1187. extern long    ARGS_ON_STACK null_datime    P_((FILEPTR *f, short *time, int rwflag));
  1188.  
  1189. DEVDRV screen_device = {
  1190.     screen_open, screen_write, screen_read, screen_lseek, screen_ioctl,
  1191.     null_datime, screen_close, screen_select, screen_unselect
  1192. };
  1193.  
  1194. static long ARGS_ON_STACK 
  1195. screen_open(f)
  1196.     FILEPTR *f;
  1197. {
  1198.  
  1199.     if (!current) {
  1200.         init();
  1201.     }
  1202.     ++scr_usecnt;
  1203.  
  1204.     f->flags |= O_TTY;
  1205.     return 0;
  1206. }
  1207.  
  1208. static long ARGS_ON_STACK 
  1209. screen_close(f, pid)
  1210.     FILEPTR *f;
  1211.     int pid;
  1212. {
  1213.     SCREEN *v = current;
  1214.     UNUSED(pid);
  1215.  
  1216.     if (v && f->links <= 0 && !--scr_usecnt) {
  1217.         if (hardbase) {
  1218.             v->curstimer = 0x7f;
  1219.             v->cursaddr = v->cursaddr + (oldbase-base);
  1220.             quickmove(oldbase, base, scrnsize);
  1221.             base = oldbase;
  1222.             Setscreen(oldbase, oldbase, -1);
  1223.             v->curstimer = v->period;
  1224.         }
  1225.         current = 0;
  1226.     }
  1227.     return 0;
  1228. }
  1229.  
  1230. static long ARGS_ON_STACK 
  1231. screen_write(f, buf, bytes)
  1232.     FILEPTR *f; const char *buf; long bytes;
  1233. {
  1234.     SCREEN *v = current;
  1235.     struct bios_file *b = (struct bios_file *)f->fc.index;
  1236.     long *r;
  1237.     long ret = 0;
  1238.     int c;
  1239.  
  1240.     UNUSED(f);
  1241.  
  1242.     (void)checkkeys();
  1243.     v->hidecnt++;
  1244.     v->flags |= CURS_UPD;        /* for TOS 1.0 */
  1245.     curs_off(v);
  1246.     r = (long *)buf;
  1247.     while (bytes > 0) {
  1248.         c = (int) *r++;
  1249.         put_ch(v, c);
  1250.         bytes -= 4; ret+= 4;
  1251.     }
  1252.     if (v->hidecnt > 0)
  1253.         --v->hidecnt;
  1254.     else
  1255.         v->hidecnt = 0;
  1256.     curs_on(v);
  1257.     v->flags &= ~CURS_UPD;
  1258.     if (ret > 0) {
  1259.         b->xattr.atime = b->xattr.mtime = timestamp;
  1260.         b->xattr.adate = b->xattr.mdate = datestamp;
  1261.     }
  1262.     return ret;
  1263. }
  1264.  
  1265. static long ARGS_ON_STACK 
  1266. screen_read(f, buf, bytes)
  1267.     FILEPTR *f; char *buf; long bytes;
  1268. {
  1269.     struct bios_file *b = (struct bios_file *)f->fc.index;
  1270.     long *r, ret = 0;
  1271.  
  1272.     r = (long *)buf;
  1273.  
  1274.     while (bytes > 0) {
  1275.         if ( (f->flags & O_NDELAY) && !bconstat(CONDEV) )
  1276.             break;
  1277.         *r++ = bconin(CONDEV) & 0x7fffffffL;
  1278.         bytes -= 4; ret += 4;
  1279.     }
  1280.     if (ret > 0) {
  1281.         b->xattr.atime = timestamp;
  1282.         b->xattr.adate = datestamp;
  1283.     }
  1284.     return ret;
  1285. }
  1286.  
  1287. static long ARGS_ON_STACK 
  1288. screen_lseek(f, where, whence)
  1289.     FILEPTR *f;
  1290.     long where;
  1291.     int whence;
  1292. {
  1293. /* terminals always are at position 0 */
  1294.     UNUSED(f); UNUSED(where);
  1295.     UNUSED(whence);
  1296.     return 0;
  1297. }
  1298.  
  1299. static long ARGS_ON_STACK 
  1300. screen_ioctl(f, mode, buf)
  1301.     FILEPTR *f; int mode; void *buf;
  1302. {
  1303.     long *r = (long *)buf;
  1304.     struct winsize *w;
  1305.  
  1306.     UNUSED(f);
  1307.  
  1308.     if (mode == FIONREAD) {
  1309.         if (bconstat(CONDEV))
  1310.             *r = 1;
  1311.         else
  1312.             *r = 0;
  1313.     }
  1314.     else if (mode == FIONWRITE) {
  1315.             *r = 1;
  1316.     }
  1317.     else if (mode == TIOCFLUSH) {
  1318. /* BUG: this should flush the input/output buffers */
  1319.         return 0;
  1320.     }
  1321.     else if (mode == TIOCGWINSZ) {
  1322.         w = (struct winsize *)buf;
  1323.         w->ws_row = current->maxy+1;
  1324.         w->ws_col = current->maxx+1;
  1325.     }
  1326.     else if (mode >= TCURSOFF && mode <= TCURSGRATE) {
  1327.         SCREEN *v = current;
  1328.         switch(mode) {
  1329.         case TCURSOFF:
  1330.             curs_off(v);
  1331.             v->hidecnt++;
  1332.             v->flags &= ~CURS_ON;
  1333.             break;
  1334.         case TCURSON:
  1335.             v->flags |= CURS_ON;
  1336.             v->hidecnt = 0;
  1337.             curs_on(v);
  1338.             break;
  1339.         case TCURSBLINK:
  1340.             curs_off(v);
  1341.             v->flags |= CURS_FLASH;
  1342.             curs_on(v);
  1343.             break;
  1344.         case TCURSSTEADY:
  1345.             curs_off(v);
  1346.             v->flags &= ~CURS_FLASH;
  1347.             curs_on(v);
  1348.             break;
  1349.         case TCURSSRATE:
  1350.             v->period = *((short *)buf);
  1351.             break;
  1352.         case TCURSGRATE:
  1353.             return v->period;
  1354.         }
  1355.     } else
  1356.         return EINVFN;
  1357.  
  1358.     return 0;
  1359. }
  1360.  
  1361. static long ARGS_ON_STACK 
  1362. screen_select(f, p, mode)
  1363.     FILEPTR *f; long p; int mode;
  1364. {
  1365.     struct tty *tty = (struct tty *)f->devinfo;
  1366.     int dev = CONDEV;
  1367.  
  1368.     if (mode == O_RDONLY) {
  1369.         if (bconstat(dev)) {
  1370.             return 1;
  1371.         }
  1372.         if (tty) {
  1373.         /* avoid collisions with other processes */
  1374.             if (!tty->rsel)
  1375.                 tty->rsel = p;
  1376.         }
  1377.         return 0;
  1378.     } else if (mode == O_WRONLY) {
  1379.         return 1;
  1380.     }
  1381.     /* default -- we don't know this mode, return 0 */
  1382.     return 0;
  1383. }
  1384.  
  1385. static void ARGS_ON_STACK 
  1386. screen_unselect(f, p, mode)
  1387.     FILEPTR *f;
  1388.     long p;
  1389.     int mode;
  1390. {
  1391.     struct tty *tty = (struct tty *)f->devinfo;
  1392.  
  1393.     if (tty) {
  1394.         if (mode == O_RDONLY && tty->rsel == p)
  1395.             tty->rsel = 0;
  1396.         else if (mode == O_WRONLY && tty->wsel == p)
  1397.             tty->wsel = 0;
  1398.     }
  1399. }
  1400.  
  1401. #endif /* FASTTEXT */
  1402.